package cn.edu.cug.cs.gtl.renders.openinventor.basics;

import cn.edu.cug.cs.gtl.apis.render.basics.Box3f;
import cn.edu.cug.cs.gtl.apis.render.basics.Matrix;
import cn.edu.cug.cs.gtl.apis.render.basics.Vec3f;
import com.openinventor.inventor.SbBox3f;
import com.openinventor.inventor.SbMatrix;
import com.openinventor.inventor.SbVec3f;

import java.util.HashMap;

public class Box3fImpl implements Box3f {
    private SbBox3f nativeObject = null;
    public Box3fImpl(){
        this.nativeObject = new SbBox3f();
    }

    public Box3fImpl(SbBox3f v){
        this.nativeObject = v;
    }
    @Override
    public Object getNativeObject() {
        return nativeObject;
    }

    @Override
    public boolean attach(Object nativeObject) {
        if(nativeObject instanceof  SbBox3f){
            this.nativeObject = (SbBox3f) nativeObject;
            return true;
        }
        return false;
    }

    @Override
    public Object detach() {
        Object r = this.nativeObject;
        this.nativeObject=null;
        return r;
    }


    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Box3f)
            return nativeObject.equals(((Box3fImpl)obj).nativeObject);
        else if(obj instanceof SbBox3f){
            return nativeObject.equals(obj);
        }
        else
            return false;
    }

    /**
     * Returns the squared maximum distance between a point and the 8 bounding box's vertices.
     *
     * @param p
     * @return
     */
    @Override
    public float computeMaxDistance2(Vec3f p) {
        return nativeObject.computeMaxDistance2((SbVec3f) p.getNativeObject());
    }

    /**
     * Returns true if the specified box is fully contained inside this box.
     *
     * @param bb
     * @return
     */
    @Override
    public boolean contains(Box3f bb) {
        return nativeObject.contains((SbBox3f) bb.getNativeObject());
    }

    /**
     * Extends this box (if necessary) to contain the specified box.
     *
     * @param bb
     */
    @Override
    public void extendBy(Box3f bb) {
        nativeObject.extendBy((SbBox3f) bb.getNativeObject());
    }

    /**
     * Extends this box (if necessary) to contain the specified point.
     *
     * @param pt
     */
    @Override
    public void extendBy(Vec3f pt) {
        nativeObject.extendBy((SbVec3f) pt.getNativeObject());
    }

    /**
     * Gets the corners of the box.
     *
     * @return
     */
    @Override
    public float[] getBounds() {
        return nativeObject.getBounds();
    }

    /**
     * Sets the corners of the box.
     *
     * @param xmin
     * @param ymin
     * @param zmin
     * @param xmax
     * @param ymax
     * @param zmax
     */
    @Override
    public void setBounds(float xmin, float ymin, float zmin, float xmax, float ymax, float zmax) {
        nativeObject.setBounds(xmin,ymin,zmin,xmax,ymax,zmax);
    }

    /**
     * Sets the corners of the box.
     *
     * @param _min
     * @param _max
     */
    @Override
    public void setBounds(Vec3f _min, Vec3f _max) {
        nativeObject.setBounds(
                (SbVec3f) _min.getNativeObject(),
                (SbVec3f) _max.getNativeObject());
    }

    /**
     * Returns the center of the box.
     *
     * @return
     */
    @Override
    public Vec3f getCenter() {
        return new Vec3fImpl(nativeObject.getCenter());
    }

    /**
     * Returns the closest point on the box to the given point.
     *
     * @param point
     * @return
     */
    @Override
    public Vec3f getClosestPoint(Vec3f point) {
        return new Vec3fImpl(nativeObject.getClosestPoint((SbVec3f) point.getNativeObject()));
    }

    /**
     * Returns the maximum point of the box.
     *
     * @return
     */
    @Override
    public Vec3f getMax() {
        return new Vec3fImpl(nativeObject.getMax());
    }

    /**
     * Returns the minimum point of the box.
     *
     * @return
     */
    @Override
    public Vec3f getMin() {
        return new Vec3fImpl(nativeObject.getMin());
    }

    /**
     * Gets the corners of the box.
     *
     * @return
     */
    @Override
    public Vec3f[] getMinMax() {
        SbVec3f [] rs = nativeObject.getMinMax();
        Vec3f [] r = new Vec3f[rs.length];
        for(int i=0;i<rs.length;++i){
            r[i] = new Vec3fImpl(rs[i]);
        }
        return r;
    }

    /**
     * Gets box origin which is the same as the minimum corner of the box.
     *
     * @return
     */
    @Override
    public float[] getOrigin() {
        return nativeObject.getOrigin();
    }

    /**
     * Gets box size.
     *
     * @return
     */
    @Override
    public Vec3f getSize() {
        return new Vec3fImpl((SbVec3f) nativeObject.getSize());
    }

    /**
     * Finds the span of a box along a specified direction.
     *
     * @param direction
     * @return
     */
    @Override
    public float[] getSpan(Vec3f direction) {
        return nativeObject.getSpan((SbVec3f) direction.getNativeObject());
    }

    @Override
    public float[] getValue() {
        return nativeObject.getValue();
    }

    /**
     * Returns the volume of the box.
     *
     * @return
     */
    @Override
    public float getVolume() {
        return nativeObject.getVolume();
    }

    /**
     * Returns true if all three dimensions of the box have positive size, and false otherwise.
     *
     * @return
     */
    @Override
    public boolean hasVolume() {
        return nativeObject.hasVolume();
    }

    /**
     * Returns true if the specified box intersects this box.
     *
     * @param bb
     * @return
     */
    @Override
    public boolean intersect(Box3f bb) {
        return nativeObject.intersect((SbBox3f) bb.getNativeObject());
    }

    /**
     * Returns true if the specified point intersects this box.
     *
     * @param pt
     * @return
     */
    @Override
    public boolean intersect(Vec3f pt) {
        return nativeObject.intersect((SbVec3f) pt.getNativeObject());
    }

    /**
     * Returns the intersection of the specified box with this box.
     *
     * @param box
     * @return
     */
    @Override
    public Box3f intersection(Box3f box) {
        return new Box3fImpl(nativeObject.intersection((SbBox3f) box.getNativeObject()));
    }

    /**
     * Returns true if the box is empty, and false otherwise.
     *
     * @return
     */
    @Override
    public boolean isEmpty() {
        return nativeObject.isEmpty();
    }

    /**
     * Makes an empty box.
     */
    @Override
    public void makeEmpty() {
        nativeObject.makeEmpty();
    }

    /**
     * Returns true if bounding box is completely outside the view-volume defined by the model+view+projection matrix given.
     *
     * @param MVP
     * @return
     */
    @Override
    public int outside(Matrix MVP) {
        return nativeObject.outside((SbMatrix) MVP.getNativeObject());
    }

    @Override
    public Box3f setValue(float[] components) {
        return new Box3fImpl(nativeObject.setValue(components));
    }

    @Override
    public Box3f setValue(float[] components, int startIndex) {
        return new Box3fImpl(nativeObject.setValue(components,startIndex));
    }

    @Override
    public void setValue(Box3f copyFrom) {
        nativeObject.setValue((SbBox3f) copyFrom.getNativeObject());
    }

    /**
     * Transforms box by matrix, enlarging box to contain result.
     *
     * @param m
     */
    @Override
    public void transform(Matrix m) {
        nativeObject.transform((SbMatrix) m.getNativeObject());
    }

    /**
     * Return true if the given triangle intersects the bounding box.
     *
     * @param u0
     * @param u1
     * @param u2
     * @return
     */
    @Override
    public boolean triangleBoxOverlap(Vec3f u0, Vec3f u1, Vec3f u2) {
        return nativeObject.triangleBoxOverlap(
                (SbVec3f) u0.getNativeObject(),
                (SbVec3f) u1.getNativeObject(),
                (SbVec3f) u2.getNativeObject()
        );
    }
}
